/*
 * formulation.c
 *
 *  Created on: 30/12/2011
 *      Author: marcio
 */

#include "formulation.h"

CPXENVptr* env;//ambiente do cplex
CPXLPptr* prob;//problema inteiro
long*** varToEdge;//mapeamento de variavel para aresta
long** edgeToVar;//mapeamento de aresta para variavel
long* var;//numero de variaveis;

extern long k;//o k da coloração
extern long* va;//a ordem dos vertices

int init(){
	setAdjMatrix(getSharedGraph());
	var = malloc(sizeof(long)*nverts());
	long i,j;

	//alocação de memoria pra edgeVar
	edgeToVar = malloc(sizeof(long**)*nverts());
	for(i = 0; i < nverts(); i++){
		var[va[i]] = 0;
		edgeToVar[va[i]] = malloc(sizeof(long*)*nverts());
	}

	//alocação de memoria para verToedge
	varToEdge = malloc(sizeof(long*)*nverts());
	for(i = 0; i < nverts(); i++){
		varToEdge[i] = malloc(sizeof(long)*nverts());
		for(j = 0; j < nverts()*k; j++){
			varToEdge[i][j] = malloc(sizeof(long)*2);
		}
	}

	for(i = 0; i < nverts(); i++){
		var[va[i]] = 0;
		for(j = i; j < nverts(); j++){
			if(hasEdge(va[i], va[j]) || i == j){
				edgeToVar[va[i]][va[j]] = var[va[i]];
				varToEdge[va[i]][var[va[i]]][0] = va[i];
				varToEdge[va[i]][var[va[i]]][1] = va[j];
				var[va[i]]++;
				//printf("var = %lu referente a %lu %lu %lu \n", var[va[i]], va[i], va[j], l);
			}
		}
	}

	env = malloc(sizeof(CPXENVptr)*nverts());
	prob = malloc(sizeof(CPXLPptr)*nverts());
	int status;

	for(i = 0; i < nverts(); i++){
		env[va[i]] = CPXopenCPLEX(&status);
		prob[va[i]] = CPXcreateprob(env[va[i]], &status, "Formulação de k-col!!!");
		double obj[nverts()];
		double lb[nverts()];
		double ub[nverts()];
		char type[nverts()];
		for(j = 0; j < nverts(); j++){
			obj[j] = 0.0;
			lb[j] = 0.0;
			ub[j] = 1.0;
			type[j] = 'C';
		}
		//cria as variavies
		CPXnewcols(env[va[i]], prob[va[i]], var[va[i]], obj, lb, ub, type, NULL);
		//defini o sentindo da função objetivo
		CPXchgobjsen(env[va[i]], prob[va[i]], CPX_MIN);
		CPXchgprobtype(env[va[i]], prob[va[i]], CPXPROB_LP);
	}
	return 0;
}

/*adiciona restrição na anti-vizinhança de v referente a u e w*/
int addEdgeConstrain(long v, long u, long w){
	setAdjMatrix(getSharedGraph());
	double rhs[1] = {0.0};//lado direito da restriçao
	char sense[1] = {'L'};// sentido da restriçao
	int rmatbeg[3] = {0,3};
	int rmatind[3];
	rmatind[0] = edgeToVar[v][u];
	rmatind[1] = edgeToVar[v][w];
	rmatind[2] = edgeToVar[v][v];
	double rmatval[3] = {1.0, 1.0, -1.0};
	CPXaddrows(env[v], prob[v], 0, 1, 3, rhs, sense, rmatbeg, rmatind, rmatval, NULL, NULL);
	return 0;
}

/*adiciona restrição de aresta a u e v*/
int addIndConstrain(long v, long u){
	setAdjMatrix(getSharedGraph());
	double rhs[1] = {0.0};//lado direito da restriçao
	char sense[1] = {'L'};// sentido da restriçao
	int rmatbeg[2] = {0,2};
	int rmatind[2];
	rmatind[0] = edgeToVar[v][u];
	rmatind[1] = edgeToVar[v][v];
	double rmatval[2] = { 1.0, -1.0};
	CPXaddrows(env[v], prob[v], 0, 1, 2, rhs, sense, rmatbeg, rmatind, rmatval, NULL, NULL);
	return 0;
}

/*Adiciona restrição de Cover referente a v*/
int changeObjCoef(double* mu){
	setAdjMatrix(getSharedGraph());
	int indices[nverts()];
	int i, j;
	for(i = 0; i < nverts(); i++)indices[i] = i;

	double coefs[nverts()];

	for(i = 0; i < nverts(); i++){
		for(j = i; j < nverts(); j++){
			if(hasEdge(va[i], va[j]) || i == j){
				if(i == j)coefs[edgeToVar[va[i]][va[i]]] = 1.0 - mu[va[i]];
				else coefs[edgeToVar[va[i]][va[j]]] = (-1)*mu[va[j]];
			}
		}
		CPXchgobj(env[va[i]], prob[va[i]], var[va[i]], indices, coefs);
	}
	return 0;
}


double solveSingleLP(int v){
	double value;
	CPXlpopt(env[va[v]], prob[va[v]]);
	CPXgetobjval(env[va[v]],prob[va[v]], &value);
	//printf("valor do subproblema de %lu = %f \n", va[v], value);
	//CPXwriteprob (env[va[v]], prob[va[v]], "problemalinear.lp", NULL);
	return value;
}


int getX(double** x){
	double y[nverts()];
	int i , j;
	for(i = 0; i < nverts(); i++){
		CPXgetx (env[va[i]], prob[va[i]], y, 0, var[va[i]]-1);
		for(j = 0; j < var[va[i]]; j++){
			x[varToEdge[va[i]][j][0]][varToEdge[va[i]][j][0]] = y[j];
		}
	}
	return 0;
}
